﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Popups;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

namespace OpenRPOSMetro
{
    /// <summary>
    /// Main page used for ordering menu items.
    /// </summary>
    public sealed partial class MainPage : Page
    {
        int iCurrentTableNumber = 0;
        bool bExclusive;
        decimal decCurrentTotal = 0;
        int iCurrentOptionGroupIndex, iCurrentMenuItemID, iCurrentSplitSeatNumber;
        Dictionary<Button, Grid> dictNavMenuCategories = new Dictionary<Button, Grid>();
        Dictionary<Button, ServiceReferenceOpenRPOS.MenuItem> dictButtonMenuItems = new Dictionary<Button, ServiceReferenceOpenRPOS.MenuItem>();
        Dictionary<string, ServiceReferenceOpenRPOS.MenuItem> dictOptionItems = new Dictionary<string, ServiceReferenceOpenRPOS.MenuItem>();
        List<OrderData> orderDataList = new List<OrderData>();
        List<int> orderSummaryIDList = new List<int>();
        OptionDialog currentOptionDialog;
        OrderData currentOrderData;
        Popup dialogPopup;
        ServiceReferenceOpenRPOS.MenuItemOptionGroup currentMenuItemOptionGroup;
        ServiceReferenceOpenRPOS.OrderSummary currentOrderSummary = new ServiceReferenceOpenRPOS.OrderSummary();

        public MainPage()
        {
            // Initialize...
            this.InitializeComponent();
            int iNavButtonCount = Globals.MenuCategoryRecords.Count(), currentButton = 0;
            double dblNavGridWidth = Windows.UI.Xaml.Window.Current.Bounds.Width - (2 * colLeftMargin.Width.Value) - colOrder.Width.Value - (2 * colRightMargin.Width.Value);
            double dblMenuGridHeight = Windows.UI.Xaml.Window.Current.Bounds.Height - rowTopMargin.Height.Value - rowNav.Height.Value - rowButtonBar.Height.Value - rowBottomMargin.Height.Value;
            double dblNavButtonWidth = (dblNavGridWidth / iNavButtonCount);
            TextBlock buttonTextBlock;

            currentOrderSummary.col_Status = Globals.k_int_status_open;
            // Create navigation buttons
            foreach (ServiceReferenceOpenRPOS.MenuCategory mc in Globals.MenuCategoryRecords)
            {
                Button navButton = new Button();
                navButton.IsEnabled = (currentButton != 0);
                navButton.Margin = new Thickness(colLeftMargin.Width.Value + (dblNavButtonWidth * currentButton++), rowTopMargin.Height.Value, 0, 0);
                navButton.Width = dblNavButtonWidth;
                navButton.Height = rowNav.Height.Value;
                buttonTextBlock = new TextBlock();
                buttonTextBlock.TextWrapping = TextWrapping.Wrap;
                buttonTextBlock.TextAlignment = TextAlignment.Center;
                buttonTextBlock.Text = mc.col_Name;
                navButton.Content = buttonTextBlock; 
                navButton.FontSize = Globals.k_dbl_nav_button_font_size;
                navButton.Click += new RoutedEventHandler(OnNavButtonClick);
                grdNav.Children.Add(navButton);
                // Create a grid for this menu category
                Grid grdMenuCategory = new Grid();
                var count = Globals.MenuItemRecords.Where(x => x.col_MenuCategoryID == mc.col_ID).Count();
                // Add buttons for items in each menu category
                if (count > 0)
                {
                    int hbuttons = (int)Math.Sqrt(count);
                    int vbuttons = count / hbuttons;
                    int hcnt = 0, vcnt = 0, cnt = 0;
                    vbuttons = (count > (hbuttons * vbuttons)) ? vbuttons + 1 : vbuttons;
                    double dblButtonWidth = (dblNavGridWidth / hbuttons) - colLeftMargin.Width.Value;
                    double dblButtonHeight = (dblMenuGridHeight / vbuttons) - colRightMargin.Width.Value;
                    foreach (ServiceReferenceOpenRPOS.MenuItem mi in Globals.MenuItemRecords.Where(x => x.col_MenuCategoryID == mc.col_ID))
                    {
                        Button btn = new Button();
                        // Size and position buttons such that they fit evenly on the screen
                        hcnt = cnt % hbuttons;
                        vcnt = cnt / hbuttons;
                        buttonTextBlock = new TextBlock();
                        buttonTextBlock.TextWrapping = TextWrapping.Wrap;
                        buttonTextBlock.TextAlignment = TextAlignment.Center;
                        buttonTextBlock.Text = mi.col_FullName;
                        btn.Content = buttonTextBlock; 
                        btn.Margin = new Thickness(hcnt * dblButtonWidth + ((hcnt + 1) * colLeftMargin.Width.Value) + (colLeftMargin.Width.Value / hbuttons) + 1,
                            vcnt * dblButtonHeight + ((vcnt + 1) * rowTopMargin.Height.Value), 0, 0);
                        btn.Width = dblButtonWidth;
                        btn.Height = dblButtonHeight;
                        btn.HorizontalAlignment = HorizontalAlignment.Left;
                        btn.VerticalAlignment = VerticalAlignment.Top;
                        if (vbuttons < Globals.k_int_small_rows)
                            btn.FontSize = Globals.k_dbl_menu_button_font_size;
                        else
                            btn.FontSize = Globals.k_dbl_menu_small_button_font_size;
                        dictButtonMenuItems[btn] = mi;
                        btn.Click += new RoutedEventHandler(OnMenuItemButtonClick);
                        grdMenuCategory.Children.Add(btn);
                        cnt++;
                    }
                }
                if (currentButton == 1)
                {
                    grdMenu.Children.Clear();
                    grdMenu.Children.Add(grdMenuCategory);
                }
                // Add this grid to the collection
                dictNavMenuCategories.Add(navButton, grdMenuCategory);
            }
            // Adjust the height of the order list...
            lvCurrentOrder.Height = dblMenuGridHeight - tblkTotal.Height;
            // Hide the manager button if the current user is not a manager
            btnManager.Visibility = (Globals.currentLogin.col_Manager ? Visibility.Visible : Visibility.Collapsed);
            // Determine whether or not to show the close and print buttons
            try
            {
                var localSettings = Windows.Storage.ApplicationData.Current.LocalSettings;
                string value = (string)localSettings.Values[Globals.k_str_settings_show_close_button].ToString().ToUpper().Trim();
                btnClose.Visibility = (value == Globals.k_str_value_yes || value == Globals.k_str_value_true || value == Globals.k_str_value_one)
                    ? Visibility.Visible : Visibility.Collapsed;
                value = localSettings.Values[Globals.k_str_settings_show_print_button].ToString().ToUpper().Trim();
                btnPrint.Visibility = (value == Globals.k_str_value_yes || value == Globals.k_str_value_true || value == Globals.k_str_value_one)
                    ? Visibility.Visible : Visibility.Collapsed;
            } catch (Exception){ }
        }

        private void OnNavButtonClick(object sender, RoutedEventArgs e)
        {
            // Disable selected button
            Button clickedButton = (Button)sender;
            clickedButton.IsEnabled = false;
            // Enable all other nav buttons
            foreach (Button navButton in grdNav.Children)
            {
                if (navButton != clickedButton)
                    navButton.IsEnabled = true;
            }
            // Display selected grid
            grdMenu.Children.Clear();
            grdMenu.Children.Add(dictNavMenuCategories[clickedButton]);
        }
        private void OnMenuItemButtonClick(object sender, RoutedEventArgs e)
        {
            Button btn = (Button)sender;
            // Add item to order
            OrderData od = new OrderData();
            od.MenuItemID = dictButtonMenuItems[btn].col_ID;
            od.MenuItemName = dictButtonMenuItems[btn].col_FullName;
            od.DisplayPrice = dictButtonMenuItems[btn].col_Price.ToString("N");
            od.Price = dictButtonMenuItems[btn].col_Price;
            decCurrentTotal += od.Price;
            tblkTotal.Text = decCurrentTotal.ToString("N");
            lvCurrentOrder.Items.Add(od);
            lvCurrentOrder.ScrollIntoView(od);
            btnSend.IsEnabled = true;
            btnClose.IsEnabled = false;
            btnPrint.IsEnabled = false;
            btnSplit.IsEnabled = true;
            btnNew.IsEnabled = true;
            // Handle pizzas differently...
            if (dictButtonMenuItems[btn].col_Pizza)
            {
                PizzaDialog pd = new PizzaDialog();
                pd.Width = Windows.UI.Xaml.Window.Current.Bounds.Width;
                pd.Height = Windows.UI.Xaml.Window.Current.Bounds.Height;
                pd.iParentMenuItemID = od.MenuItemID;
                pd.init();
                pd.CloseRequested += PizzaDialog_CloseRequested;
                od.Options = new List<OrderData>();
                od.Options.Clear();
                currentOrderData = od;
                dialogPopup = new Popup();
                dialogPopup.Child = pd;
                dialogPopup.IsOpen = true;
            }
            else // Non-pizza
            {
                // Determine if any option groups exist...
                if (Globals.MenuItemOptionGroupRecords.Where(x => x.col_MenuItemID == dictButtonMenuItems[btn].col_ID).Count() > 0)
                {
                    iCurrentOptionGroupIndex = 0;
                    iCurrentMenuItemID = dictButtonMenuItems[btn].col_ID;
                    currentMenuItemOptionGroup = Globals.MenuItemOptionGroupRecords.Where(x => x.col_MenuItemID == iCurrentMenuItemID).ElementAt(iCurrentOptionGroupIndex++);
                    od.Options = new List<OrderData>();
                    od.Options.Clear();
                    currentOrderData = od;
                    createOptionGroupDialog();
                }
            }
        }
        private void PizzaDialog_CloseRequested(object sender, EventArgs e)
        {
            dialogPopup.IsOpen = false;
            // Update slip with pizza information...
            PizzaDialog pd = (PizzaDialog)sender;
            foreach(OrderData od in pd.orderDataList)
            {
                od.MenuItemName = "  " + od.MenuItemName;
                od.Parent = currentOrderData;
                currentOrderData.Options.Add(od);
                decCurrentTotal += od.Price;
                tblkTotal.Text = decCurrentTotal.ToString("N");
                lvCurrentOrder.Items.Add(od);
                lvCurrentOrder.ScrollIntoView(od);
            }
        }
        private async void btnLogout_Click(object sender, RoutedEventArgs e)
        {
            // Prompt the user before logging out
            var messageDialog = new MessageDialog("Are you sure you want to logout?");
            // Add commands and set their callbacks; both buttons use the same callback function instead of inline event handlers
            IUICommand icmdYes = new UICommand("Yes");
            IUICommand icmdNo = new UICommand("No");
            messageDialog.Commands.Add(icmdYes);
            messageDialog.Commands.Add(icmdNo);
            // Show the message dialog
            if (await messageDialog.ShowAsync() == icmdYes)
            {
                // Return to the login screen...
                Frame rootFrame = Window.Current.Content as Frame;
                rootFrame.Navigate(typeof(Login), e);
            }
        }
        void createOptionGroupDialog()
        {
            OptionDialog od = new OptionDialog();
            od.Width = Windows.UI.Xaml.Window.Current.Bounds.Width;
            od.Height = Windows.UI.Xaml.Window.Current.Bounds.Height;
            Dictionary<string, int> dictMenuItems = new Dictionary<string, int>();
            Dictionary<string, bool> dictMenuItemChecked = new Dictionary<string, bool>();
            ServiceReferenceOpenRPOS.OptionGroup og = Globals.OptionGroupRecords.Where(x => x.col_ID == currentMenuItemOptionGroup.col_OptionGroupID).First();
            dictOptionItems.Clear();
            // Determine the number of options
            foreach (ServiceReferenceOpenRPOS.MenuOption mo in Globals.MenuOptionRecords.Where(x => x.col_OptionGroupID == currentMenuItemOptionGroup.col_OptionGroupID))
            {
                if (Globals.MenuItemRecords.Where(x => x.col_ID == mo.col_MenuItemID).Count() > 0)
                {
                    ServiceReferenceOpenRPOS.MenuItem mi = Globals.MenuItemRecords.Where(x => x.col_ID == mo.col_MenuItemID).First();
                    dictMenuItems.Add(mi.col_FullName, mi.col_ID);
                    dictOptionItems.Add(mi.col_FullName, mi);
                    dictMenuItemChecked.Add(mi.col_FullName, mo.col_Checked);
                }
            }
            // Display options in alphabetical order
            var list = dictMenuItems.Keys.ToList();
            list.Sort();
            int cnt = 0;
            bExclusive = og.col_Exclusive;
            double dblScale = 2;// (list.Count() < 10) ? 2 : 1.5;
            double dblCheckboxHeight = (list.Count() < 10) ? Globals.k_dbl_checkbox_height : Globals.k_dbl_small_checkbox_height;
            int iNumCols = ((list.Count() - 1) / Globals.k_int_max_options_per_column) + 1;
            int iCurrCol = 0;
            // Iterate over the options in the group
            foreach (var key in list)
            {
                // Double the size of the options for easier selection
                ScaleTransform st = new ScaleTransform();
                st.ScaleX = dblScale;
                st.ScaleY = dblScale;
                // Use radio buttons for an exclusive option group
                if (bExclusive)
                {
                    RadioButton rb = new RadioButton();
                    rb.Content = key;
                    rb.Height = Globals.k_dbl_radio_button_height;
                    if (cnt == 0) rb.IsChecked = true;
                    //rb.Margin = new Thickness(Globals.k_dbl_button_spacing * dblScale, (cnt++ * rb.Height * dblScale) + Globals.k_dbl_radio_button_height, 0, 0);
                    rb.Margin = new Thickness(Globals.k_dbl_button_spacing + (iCurrCol * Globals.k_dbl_option_group_width),
                        (cnt * Globals.k_dbl_radio_button_height * dblScale) + Globals.k_dbl_radio_button_height, 0, 0);
                    rb.Padding = new Thickness(Globals.k_dbl_option_padding, Globals.k_dbl_option_padding, 0, 0);
                    rb.HorizontalAlignment = HorizontalAlignment.Left;
                    rb.VerticalAlignment = VerticalAlignment.Top;
                    rb.RenderTransform = st;
                    od.addUIElement(rb);
                    iCurrCol = (iCurrCol + 1) % iNumCols;
                    cnt = (iCurrCol == 0) ? cnt + 1 : cnt;
                }
                else // Used check-box for non-exclusive (multiple options allowed) group
                {
                    CheckBox cb = new CheckBox();
                    cb.Content = key;
                    cb.Height = dblCheckboxHeight;
                    cb.Margin = new Thickness(Globals.k_dbl_button_spacing + (iCurrCol * Globals.k_dbl_option_group_width),
                        (cnt * Globals.k_dbl_checkbox_height * dblScale) + Globals.k_dbl_checkbox_height, 0, 0);
                    cb.Padding = new Thickness(Globals.k_dbl_option_padding, Globals.k_dbl_option_padding, 0, 0);
                    cb.RenderTransform = st;
                    cb.IsChecked = dictMenuItemChecked[key];
                    cb.HorizontalAlignment = HorizontalAlignment.Left;
                    cb.VerticalAlignment = VerticalAlignment.Top;
                    od.addUIElement(cb);
                    iCurrCol = (iCurrCol + 1) % iNumCols;
                    cnt = (iCurrCol == 0) ? cnt + 1 : cnt;
                }
            }
            // Size the dialog
            od.innerDialog.Width = (Globals.k_dbl_option_group_width * iNumCols) + (2 * Globals.k_dbl_button_spacing);
            cnt = (list.Count() < Globals.k_int_max_options_per_column) ? list.Count() : (list.Count() / iNumCols);
            cnt += ((list.Count() % iNumCols) == 0) ? 0 : 1;
            od.innerDialog.Height = dblScale * cnt * (og.col_Exclusive ? Globals.k_dbl_radio_button_height : Globals.k_dbl_checkbox_height) + Globals.k_dbl_option_group_min_height;
            currentOptionDialog = od;
            od.CloseRequested += Dialog_CloseRequested;
            dialogPopup = new Popup();
            dialogPopup.Child = od;
            dialogPopup.IsOpen = true;
        }
        private bool isDefaultOption(int optionGroupID, int optionMenuItemID)
        {
            return Globals.MenuOptionRecords.Where(x => x.col_OptionGroupID == optionGroupID && x.col_MenuItemID == optionMenuItemID).First().col_Checked;
        }
        private void Dialog_CloseRequested(object sender, EventArgs e)
        {
            dialogPopup.IsOpen = false;
            // Add selected options...
            if (bExclusive)
            {
                // Identify the selected item
                foreach (UIElement uie in currentOptionDialog.innerDialog.Children)
                {
                    if (uie.GetType().ToString().Contains("RadioButton"))
                    {
                        RadioButton rb = (RadioButton)uie;
                        if (rb.IsChecked == true) // Selected
                        {
                            // Add item to order
                            OrderData od = new OrderData();
                            string rbContent = "";
                            if (rb.Content != null) rbContent = rb.Content.ToString(); //added null check to prevent error in string conversation for null value in key 
                            od.MenuItemID = dictOptionItems[rbContent].col_ID;
                            od.MenuItemName = "  " + dictOptionItems[rbContent].col_FullName;
                            od.DisplayPrice = (dictOptionItems[rbContent].col_Price > 0 ? dictOptionItems[rbContent].col_Price.ToString("N") : "");
                            od.Price = dictOptionItems[rbContent].col_Price;
                            od.Exclusive = true;
                            od.Parent = currentOrderData;
                            currentOrderData.Options.Add(od);
                            decCurrentTotal += od.Price;
                            tblkTotal.Text = decCurrentTotal.ToString("N");
                            lvCurrentOrder.Items.Add(od);
                            lvCurrentOrder.ScrollIntoView(od);
                        }
                    }
                }
            }
            else
            {
                // Identify the selected item
                foreach (UIElement uie in currentOptionDialog.innerDialog.Children)
                {
                    if (uie.GetType().ToString().Contains("CheckBox"))
                    {
                        CheckBox cb = (CheckBox)uie;
                        if (cb.IsChecked == true) // Selected
                        {
                            // Determine if this is a default option
                            //if (!isDefaultOption(currentMenuItemOptionGroup.col_OptionGroupID, dictOptionItems[cb.Content.ToString()].col_ID))
                            if(!Globals.MenuOptionRecords.Where(x => x.col_OptionGroupID == currentMenuItemOptionGroup.col_OptionGroupID 
                                && x.col_MenuItemID == dictOptionItems[cb.Content.ToString()].col_ID).First().col_Checked)
                            {
                                // Add item to order
                                OrderData od = new OrderData();
                                od.MenuItemID = dictOptionItems[cb.Content.ToString()].col_ID;
                                od.MenuItemName = "  Add " + dictOptionItems[cb.Content.ToString()].col_FullName;
                                od.DisplayPrice = (dictOptionItems[cb.Content.ToString()].col_Price > 0 ? dictOptionItems[cb.Content.ToString()].col_Price.ToString("N") : "");
                                od.Price = dictOptionItems[cb.Content.ToString()].col_Price;
                                od.Exclusive = false;
                                od.Parent = currentOrderData;
                                decCurrentTotal += od.Price;
                                currentOrderData.Options.Add(od);
                                tblkTotal.Text = decCurrentTotal.ToString("N");
                                lvCurrentOrder.Items.Add(od);
                                lvCurrentOrder.ScrollIntoView(od);
                            }
                        } else if(Globals.MenuOptionRecords.Where(x => x.col_OptionGroupID == currentMenuItemOptionGroup.col_OptionGroupID 
                                && x.col_MenuItemID == dictOptionItems[cb.Content.ToString()].col_ID).First().col_Checked)
                            // Handle the case where the default option is un-selected
                        {
                            OrderData od = new OrderData();
                            od.MenuItemID = dictOptionItems[cb.Content.ToString()].col_ID;
                            od.MenuItemName = "  No " + dictOptionItems[cb.Content.ToString()].col_FullName;
                            od.DisplayPrice = "";
                            od.Price = 0;
                            od.Exclusive = false;
                            od.Parent = currentOrderData;
                            decCurrentTotal += od.Price;
                            currentOrderData.Options.Add(od);
                            tblkTotal.Text = decCurrentTotal.ToString("N");
                            lvCurrentOrder.Items.Add(od);
                            lvCurrentOrder.ScrollIntoView(od);
                        }
                    }
                }
            }
            // Determine if another option dialog needs to be displayed
            if (Globals.MenuItemOptionGroupRecords.Where(x => x.col_MenuItemID == iCurrentMenuItemID).Count() > iCurrentOptionGroupIndex)
            {
                // Display the next option group
                currentMenuItemOptionGroup = Globals.MenuItemOptionGroupRecords.Where(x => x.col_MenuItemID == iCurrentMenuItemID).ElementAt(iCurrentOptionGroupIndex++);
                createOptionGroupDialog();
            }
        }

        private void lvCurrentOrder_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (lvCurrentOrder.SelectedItems.Count > 0)
            {
                btnDelete.IsEnabled = true;
                foreach (OrderData od in lvCurrentOrder.SelectedItems)
                    // Do not allow exclusive options or discounts to be deleted from the list...
                    if (od.Exclusive || od.Discount)
                        lvCurrentOrder.SelectedItems.Remove(od);
            }
            else btnDelete.IsEnabled = false;
        }

        private void recalculateTotal()
        {
            decCurrentTotal = 0;
            foreach (OrderData od in lvCurrentOrder.Items)
            {
                decCurrentTotal += od.Price;
            }
            tblkTotal.Text = decCurrentTotal.ToString("N");
        }

        private async Task<Boolean> showNetworkErrorDialog()
        {
            // Prompt the user before logging out
            var messageDialog = new MessageDialog("A network error has occurred.");
            // Add commands and set their callbacks; both buttons use the same callback function instead of inline event handlers
            IUICommand icmdTryAgain = new UICommand("Try Again");
            messageDialog.Commands.Add(icmdTryAgain);
            messageDialog.Commands.Add(new UICommand("Close"));
            // Show the message dialog
            return (await messageDialog.ShowAsync() == icmdTryAgain);
        }

        private async void promptNetworkErrorOnSend()
        {
            if (await showNetworkErrorDialog())
                await sendOrder();
        }

        private async void promptNetworkErrorOnClose()
        {
            if (await showNetworkErrorDialog())
                await closeCurrentOrder();
        }

        private async void promptNetworkErrorOnGetOpenOrders()
        {
            if (await showNetworkErrorDialog())
                await getOpenOrders();
        }

        private async void promptNetworkErrorOnOpenOrdersSelectionChanged()
        {
            if (await showNetworkErrorDialog())
                cmbOpenOrders_SelectionChanged(null, null);
        }

        private async Task<Boolean> sendOrder(bool bFilterStatus = true)
        {
            btnSend.IsEnabled = false;
            // Display the wait page...
            WaitPage waitPage = new WaitPage();
            waitPage.Width = Windows.UI.Xaml.Window.Current.Bounds.Width;
            waitPage.Height = Windows.UI.Xaml.Window.Current.Bounds.Height;
            dialogPopup = new Popup();
            dialogPopup.Child = waitPage;
            dialogPopup.IsOpen = true;
            // Determine if this is a new order
            if (currentOrderSummary.col_Status == Globals.k_int_status_open)
            {
                currentOrderSummary.bFilterStatus = bFilterStatus;
                currentOrderSummary.bFilterTimeOpened = true;
                currentOrderSummary.bFilterLoginID = true;
                currentOrderSummary.col_LoginID = Globals.currentLogin.col_ID;
                currentOrderSummary.col_TimeOpened= DateTime.Now;
                currentOrderSummary.col_Status = Globals.k_int_status_sent;
            }
            currentOrderSummary.bFilterSplit = true;
            currentOrderSummary.bFilterSplitEvenly = true;
            currentOrderSummary.bFilterTableNumber = true;
            currentOrderSummary.bFilterSubtotal = true;
            currentOrderSummary.bFilterTimeSent = true;
            currentOrderSummary.bFilterCarryOut = true;
            // Ensure only numbers are entered
            try
            {
                if (tbTable.Text.Trim().Length > 0)
                    currentOrderSummary.col_TableNumber = Convert.ToInt16(tbTable.Text.Trim());
                else
                    currentOrderSummary.col_TableNumber = 0;
            }
            catch (System.FormatException)
            {
                currentOrderSummary.col_TableNumber = 0;
            }
            tbTable.Text = currentOrderSummary.col_TableNumber.ToString();
            currentOrderSummary.col_Subtotal = decCurrentTotal;
            Globals.OrderDetailRecords = new ObservableCollection<ServiceReferenceOpenRPOS.OrderDetail>();
            Globals.OrderOptionRecords = new ObservableCollection<ServiceReferenceOpenRPOS.OrderOption>();
            int iOrderDetailID = 0;
            // Traverse the list of order items and send those to the database
            foreach (OrderData orderData in lvCurrentOrder.Items)
            {
                if (orderData.Parent == null && !orderData.Discount)
                {
                    iOrderDetailID++;
                    // Add a new order detail item
                    ServiceReferenceOpenRPOS.OrderDetail orderDetail = new ServiceReferenceOpenRPOS.OrderDetail();
                    orderDetail.bFilterOrderSummaryID = true;
                    orderDetail.bFilterMenuItemID = true;
                    orderDetail.bFilterPrice = true;
                    orderDetail.bFilterSeatNumber = true;
                    orderDetail.bFilterDiscountID = true;
                    orderDetail.col_OrderSummaryID = currentOrderSummary.col_ID;
                    orderDetail.col_MenuItemID = orderData.MenuItemID;
                    orderDetail.col_Price = orderData.Price;
                    orderDetail.col_ID = iOrderDetailID;
                    orderDetail.col_SeatNumber = (byte)orderData.SeatNumber;
                    orderDetail.col_DiscountID = orderData.DiscountID;
                    Globals.OrderDetailRecords.Add(orderDetail);
                    // Check for options
                    if (orderData.Options != null)
                        foreach (OrderData odOption in orderData.Options)
                        {
                            ServiceReferenceOpenRPOS.OrderOption orderOption = new ServiceReferenceOpenRPOS.OrderOption();
                            orderOption.bFilterMenuItemID = true;
                            orderOption.bFilterOrderDetailID = true;
                            orderOption.bFilterExclusive = true;
                            orderOption.bFilterExclude = true;
                            orderOption.bFilterPrice = true;
                            orderOption.bFilterDiscountID = true;
                            orderOption.col_Exclusive = odOption.Exclusive;
                            orderOption.col_Exclude = odOption.Exclude;
                            orderOption.col_MenuItemID = odOption.MenuItemID;
                            orderOption.col_OrderDetailID = orderDetail.col_ID;
                            orderOption.col_Price = (odOption.Exclude ? 0 : odOption.Price);
                            orderOption.col_DiscountID = odOption.DiscountID;
                            Globals.OrderOptionRecords.Add(orderOption);
                        }
                }
            }
            try
            {
                currentOrderSummary.col_TimeSent = DateTime.Now;
                int iOrderSummaryID = await Globals.client.SendOrderAsync(Globals.token, currentOrderSummary, Globals.OrderDetailRecords, Globals.OrderOptionRecords);
                if (currentOrderSummary.col_ID == 0) currentOrderSummary.col_ID = iOrderSummaryID;
                
                //Update Table to mark as Occupied
                ReleaseOccupiedTable(iCurrentTableNumber); //if occupied table is changed for selected order, then release old table.
                UpdateTableSepcification(currentOrderSummary.col_TableNumber, true);

                // Update the print queue to print the order
                ServiceReferenceOpenRPOS.PrintQueue pq = new ServiceReferenceOpenRPOS.PrintQueue();
                pq.bFilterPrintOrder = true;
                pq.col_PrintOrder = true;
                pq.bFilterOrderSummaryID = true;
                pq.col_OrderSummaryID = currentOrderSummary.col_ID;
                pq.bFilterPrinted = true;
                pq.col_Printed = false;
                await Globals.client.AddPrintQueueObjectAsync(Globals.token, pq);
            }
            catch (Exception ex)
            {
                // Determine if a network error occurred
                System.Diagnostics.Debug.WriteLine(ex.Message);
                promptNetworkErrorOnSend();
            }
            finally
            {
                // Close the wait page...
                dialogPopup.IsOpen = false;
            }
            return true;
        }

        private async void UpdateTableSepcification(int tblNumber, bool isOccupied)
        {
            if (tblNumber <= 0) return; //There is nothing needs to do, in-case there is no valid table.
            try
            {
                Globals.TableSpecificationRecords = await Globals.client.GetTableSpecificationObjectsAsync(Globals.token, "1=1");

                ServiceReferenceOpenRPOS.TableSpecification tbl = Globals.TableSpecificationRecords.Where(tb => tb.col_TableNumber == tblNumber).FirstOrDefault();
                tbl.bFilterOccupied = true;
                tbl.col_Occupied = isOccupied;
                await Globals.client.UpdateTableSpecificationObjectAsync(Globals.token, tbl);
            }
            catch { }
            finally
            {
                if (isOccupied) iCurrentTableNumber = tblNumber;
                else iCurrentTableNumber = 0;
            }
        }

        private async void ReleaseOccupiedTable(int tblNumber)
        {
            if (tblNumber <= 0) return; //There is nothing needs to do, in-case there is no valid table.
            Globals.TableSpecificationRecords = await Globals.client.GetTableSpecificationObjectsAsync(Globals.token, "1=1");
            
            int countOrders = 0;
            try
            {
                //check if table is not associated with any open (non-closed) order, marked as available
                countOrders = Globals.OrderSummaryRecords.Where(os => os.col_TableNumber == tblNumber && os.col_Status != Globals.k_int_status_closed).Count();
            }
            catch { }
            if (countOrders <= 0)
            {
                UpdateTableSepcification(tblNumber, false);
            }
        }

        private async Task<Boolean> closeCurrentOrder()
        {
            // Disable the "send" button
            btnSend.IsEnabled = false;
            // Disable the "close" button
            btnClose.IsEnabled = false;
            btnPrint.IsEnabled = false;
            // Disable the "split" button
            btnSplit.IsEnabled = false;
            // Disable the "new" button
            btnNew.IsEnabled = false;
            // Close the check
            currentOrderSummary.bFilterTableNumber = true;
            currentOrderSummary.bFilterStatus = true;
            currentOrderSummary.bFilterSubtotal = true;
            currentOrderSummary.col_Subtotal = decCurrentTotal;
            currentOrderSummary.col_Status = Globals.k_int_status_closed;
            // Ensure only numbers are entered
            try
            {
                if (tbTable.Text.Trim().Length > 0)
                    currentOrderSummary.col_TableNumber = Convert.ToInt16(tbTable.Text.Trim());
                else
                    currentOrderSummary.col_TableNumber = 0;
            }
            catch (System.FormatException)
            {
                currentOrderSummary.col_TableNumber = 0;
            }
            tbTable.Text = currentOrderSummary.col_TableNumber.ToString();
            try
            {
                await Globals.client.UpdateOrderSummaryObjectAsync(Globals.token, currentOrderSummary);
                lvCurrentOrder.Items.Clear();
                currentOrderSummary = new ServiceReferenceOpenRPOS.OrderSummary();
                recalculateTotal();
                await getOpenOrders();
                tbTable.Text = "0";
                OnNavButtonClick(grdNav.Children[0], null);
                cmbOpenOrders.SelectedIndex = -1;
            }
            catch (Exception ex)
            {
                // Determine if a network error occurred
                System.Diagnostics.Debug.WriteLine(ex.Message);
                promptNetworkErrorOnClose();
            }
            //
            ReleaseOccupiedTable(iCurrentTableNumber); //Release Occupied table once order is closed.
            //
            return true;
        }
        public async Task<Boolean> getOpenOrders()
        {
            try
            {
                // Return any non-closed orders
                string filter = "status!=" + Globals.k_int_status_closed.ToString();
                // Only Managers have the ability to view/edit other checks...
                if (!Globals.currentLogin.col_Manager)
                    filter += " and LoginID=" + Globals.currentLogin.col_ID.ToString();
                Globals.OrderSummaryRecords = await Globals.client.GetOrderSummaryObjectsAsync(Globals.token, filter);
                // Add open orders to the combo box
                cmbOpenOrders.Items.Clear();
                orderSummaryIDList.Clear();
                foreach (ServiceReferenceOpenRPOS.OrderSummary os in Globals.OrderSummaryRecords)
                {
                    string strComboBoxItemText = Globals.LoginRecords.Where(x => x.col_ID == os.col_LoginID).First().col_DisplayName;
                    strComboBoxItemText += " - Table " + os.col_TableNumber.ToString() + ", # " + (os.col_ID).ToString();
                    cmbOpenOrders.Items.Add(strComboBoxItemText);
                    orderSummaryIDList.Add(os.col_ID);
                }
            }
            catch (Exception ex)
            {
                // Determine if a network error occurred
                System.Diagnostics.Debug.WriteLine(ex.Message);
                promptNetworkErrorOnGetOpenOrders();
            }
            return true;
        }

        private void btnDelete_Click(object sender, RoutedEventArgs e)
        {
            // Remove selected items from the list            
            orderDataList.Clear();
            foreach (OrderData od in lvCurrentOrder.SelectedItems)
            {
                if (!od.Exclusive)
                    if (lvCurrentOrder.SelectedItems.Contains(od))
                        orderDataList.Add(od);
            }
            foreach (OrderData od in orderDataList)
            {
                if (od.Options != null)
                    foreach (OrderData odOption in od.Options)
                    {
                        // Remove the option from the list
                        lvCurrentOrder.Items.Remove(odOption);
                    }
                // Don't remove exclusive options...
                if (!od.Exclusive)
                {
                    // Clear the option from the parent, if one exists
                    if (od.Parent != null)
                        od.Parent.Options.Remove(od);
                    lvCurrentOrder.Items.Remove(od);
                }
            }
            lvCurrentOrder.SelectedItems.Clear();
            recalculateTotal();
            btnSend.IsEnabled = true;
        }
        private void setTableNumber(int iAddValue)
        {
            int iCurrentTable;
            try
            {
                if (tbTable.Text.Trim().Length > 0)
                    iCurrentTable = Convert.ToInt16(tbTable.Text.Trim());
                else
                    iCurrentTable = 0;
            }
            catch (System.FormatException)
            {
                iCurrentTable = 0;
            }
            iCurrentTable += iAddValue;
            // Ensure the current table is in the range 0-100
            iCurrentTable = (iCurrentTable > Globals.k_int_max_tables ? Globals.k_int_max_tables : (iCurrentTable < 0 ? 0 : iCurrentTable));
            tbTable.Text = iCurrentTable.ToString();
        }
        private void btnTableUp_Click(object sender, RoutedEventArgs e)
        {
            // Set the current table number to the next table number
            setTableNumber(1);
        }

        private void btnTableDown_Click(object sender, RoutedEventArgs e)
        {
            // Set the current table number to the previous table number
            setTableNumber(-1);
        }

        private async void btnSend_Click(object sender, RoutedEventArgs e)
        {
            await sendOrder();
        }

        private async void Page_Loaded(object sender, RoutedEventArgs e)
        {
            await getOpenOrders();
        }
        private async Task<Boolean> updateDiscount(int iDiscountID, decimal dPreDiscountAmount, string strPad = "")
        {
            decimal dDiscountDollarAmt;
            ServiceReferenceOpenRPOS.Discount discountObject;
            if (Globals.DiscountRecords.Where(x => x.col_ID == iDiscountID).Count() == 0)
            {
                ObservableCollection<ServiceReferenceOpenRPOS.Discount> DiscountRecords = await Globals.client.GetDiscountObjectsAsync(Globals.token, "ID=" + iDiscountID.ToString());
                discountObject = DiscountRecords.First();
                Globals.DiscountRecords.Add(discountObject);
            }
            else
                discountObject = Globals.DiscountRecords.Where(x => x.col_ID == iDiscountID).First();
            // Only show non-zero discounts
            if (discountObject.col_Amount != 0)
            {
                OrderData orderDiscountData = new OrderData();
                orderDiscountData.Discount = true;
                orderDiscountData.DiscountID = discountObject.col_ID;
                if (discountObject.col_IsPercent)
                {
                    dDiscountDollarAmt = (-1 * (discountObject.col_Amount / 100) * dPreDiscountAmount);
                    orderDiscountData.DisplayPrice = dDiscountDollarAmt.ToString("N");
                    orderDiscountData.MenuItemName = strPad + "*** Discount - " + discountObject.col_Amount.ToString("N") + "%";
                }
                else
                {
                    dDiscountDollarAmt = (-1 * discountObject.col_Amount);
                    orderDiscountData.DisplayPrice = dDiscountDollarAmt.ToString("N");
                    orderDiscountData.MenuItemName = strPad + "*** Discount ";
                }
                orderDiscountData.FontColor = "Red";
                lvCurrentOrder.Items.Add(orderDiscountData);
                lvCurrentOrder.ScrollIntoView(orderDiscountData);
                decCurrentTotal += dDiscountDollarAmt;
            }
            return true;
        }
        private async Task<Boolean> loadSelectedOrder()
        {
            if (cmbOpenOrders.SelectedIndex >= 0)
                try
                {
                    // Display the wait page...
                    WaitPage waitPage = new WaitPage();
                    waitPage.Width = Windows.UI.Xaml.Window.Current.Bounds.Width;
                    waitPage.Height = Windows.UI.Xaml.Window.Current.Bounds.Height;
                    dialogPopup = new Popup();
                    dialogPopup.Child = waitPage;
                    dialogPopup.IsOpen = true;
                    // Clear out the current order information
                    lvCurrentOrder.Items.Clear();
                    // Initialize the running total...
                    decCurrentTotal = 0;
                    // Get the selected order
                    currentOrderSummary = Globals.OrderSummaryRecords.Where(x => x.col_ID == orderSummaryIDList[cmbOpenOrders.SelectedIndex]).First();

                    //set Existing Table Number of selected order
                    iCurrentTableNumber = currentOrderSummary.col_TableNumber;

                    tbTable.Text = currentOrderSummary.col_TableNumber.ToString();
                    currentOrderSummary.bFilterTableNumber = true;
                    await Globals.client.UpdateOrderSummaryObjectAsync(Globals.token, currentOrderSummary);
                    Globals.OrderDetailRecords = await Globals.client.GetOrderDetailObjectsAsync(Globals.token, "OrderSummaryID=" + currentOrderSummary.col_ID.ToString() + " order by ID");
                    if (Globals.OrderDetailRecords.Count() > 0)
                    {
                        string strOrderDetailIDs = "(";
                        foreach (ServiceReferenceOpenRPOS.OrderDetail od in Globals.OrderDetailRecords)
                        {
                            strOrderDetailIDs += od.col_ID.ToString() + ",";
                        }
                        strOrderDetailIDs = strOrderDetailIDs.Substring(0, strOrderDetailIDs.Length - 1) + ")";
                        Globals.OrderOptionRecords = await Globals.client.GetOrderOptionObjectsAsync(Globals.token, "OrderDetailID in " + strOrderDetailIDs + " order by ID");
                        // Add item to order
                        foreach (ServiceReferenceOpenRPOS.OrderDetail od in Globals.OrderDetailRecords)
                        {
                            // Add the order item
                            OrderData orderData = new OrderData();
                            ServiceReferenceOpenRPOS.MenuItem mi = Globals.MenuItemRecords.Where(x => x.col_ID == od.col_MenuItemID).First();
                            orderData.MenuItemID = mi.col_ID;
                            orderData.MenuItemName = mi.col_FullName;
                            orderData.DisplayPrice = od.col_Price.ToString("N");
                            orderData.Price = mi.col_Price;
                            orderData.SeatNumber = od.col_SeatNumber;
                            orderData.DiscountID = od.col_DiscountID;                            
                            decCurrentTotal += orderData.Price;
                            tblkTotal.Text = decCurrentTotal.ToString("N");
                            lvCurrentOrder.Items.Add(orderData);
                            lvCurrentOrder.ScrollIntoView(orderData);
                            // Check for discount...
                            if (orderData.DiscountID != 0)
                            {
                                await updateDiscount(orderData.DiscountID, orderData.Price, " ");
                            }
                            // Add options...
                            if (Globals.OrderOptionRecords.Where(x => x.col_OrderDetailID == od.col_ID).Count() > 0)
                            {
                                orderData.Options = new List<OrderData>();
                                foreach (ServiceReferenceOpenRPOS.OrderOption oo in Globals.OrderOptionRecords.Where(x => x.col_OrderDetailID == od.col_ID))
                                {
                                    OrderData orderOptionData = new OrderData();
                                    ServiceReferenceOpenRPOS.MenuItem miOption = Globals.MenuItemRecords.Where(x => x.col_ID == oo.col_MenuItemID).First();
                                    orderOptionData.MenuItemID = miOption.col_ID;
                                    orderOptionData.MenuItemName = "  " + (oo.col_Exclude ? "No " : (mi.col_Pizza&&(!miOption.col_Pizza) ? "Add " : "")) + miOption.col_FullName;
                                    orderOptionData.DisplayPrice = (oo.col_Price>0)?oo.col_Price.ToString("N"):""; 
                                    orderOptionData.Price = oo.col_Price; 
                                    orderOptionData.Exclusive = oo.col_Exclusive;
                                    orderOptionData.Exclude = oo.col_Exclude;
                                    orderData.Options.Add(orderOptionData);
                                    orderOptionData.Parent = orderData;
                                    decCurrentTotal += orderOptionData.Price;
                                    lvCurrentOrder.Items.Add(orderOptionData);
                                    lvCurrentOrder.ScrollIntoView(orderOptionData);
                                    // Check for discount...
                                    if (orderOptionData.DiscountID != 0)
                                    {
                                        await updateDiscount(orderOptionData.DiscountID, orderOptionData.Price, "   ");
                                    }
                                }
                            }
                        }
                        // If the summary record is attached to a discount, display the discount
                        if (currentOrderSummary.col_DiscountID != 0)
                        {
                            await updateDiscount(currentOrderSummary.col_DiscountID, decCurrentTotal);
                        }
                    }
                    tblkTotal.Text = decCurrentTotal.ToString("N");
                }
                catch (Exception ex)
                {
                    // Determine if a network error occurred
                    System.Diagnostics.Debug.WriteLine(ex.Message);
                    promptNetworkErrorOnOpenOrdersSelectionChanged();
                }
                finally
                {
                    // Enable the "close" button
                    btnClose.IsEnabled = true;
                    btnPrint.IsEnabled = false;
                    // Enable the "new" button
                    btnNew.IsEnabled = true;
                    // Enable the "split" button
                    btnSplit.IsEnabled = true;
                    // Disable the "send" button
                    btnSend.IsEnabled = false;
                    // Remove the wait page...
                    dialogPopup.IsOpen = false;
                }
            return true;
        }
        private async void cmbOpenOrders_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if ((cmbOpenOrders.SelectedIndex >= 0) && (cmbOpenOrders.SelectedIndex != orderSummaryIDList.IndexOf(currentOrderSummary.col_ID)))
            {
                // Send the check (if needed)
                if (btnSend.IsEnabled)
                    await sendOrder();
                await loadSelectedOrder();
            }
        }

        private async void cmbOpenOrders_DropDownOpened(object sender, object e)
        {
            // Ensure that all current orders are being displayed...
            await getOpenOrders();
        }

        private async void btnClose_Click(object sender, RoutedEventArgs e)
        {
            // Get the order check records
            Globals.OrderCheckRecords = await Globals.client.GetOrderCheckObjectsAsync(Globals.token, "OrderSummaryID=" + currentOrderSummary.col_ID.ToString() + " ORDER BY SeatNumber");

            foreach (ServiceReferenceOpenRPOS.OrderCheck oc in Globals.OrderCheckRecords)
            {
                // set Sub total if we call close Order 
                oc.col_Subtotal = 0;
            }

            // Ensure that the current summary record has at least 1 check associated with it
            if (currentOrderSummary.col_Split == 0)
                currentOrderSummary.col_Split = 1;
            // Determine if order checks exist for this check.  If not, create 1 for every split
            while (Globals.OrderCheckRecords.Count < currentOrderSummary.col_Split)
            {
                // Create a new order check record
                ServiceReferenceOpenRPOS.OrderCheck oc = new ServiceReferenceOpenRPOS.OrderCheck();
                // Set the filters
                oc.bFilterGratuity = true;
                oc.bFilterOrderSummaryID = true;
                oc.bFilterPaid = true;
                oc.bFilterPaymentType = true;
                oc.bFilterSeatNumber = true;
                oc.bFilterSubtotal = true;
                oc.bFilterTax = true;
                // Set the order summary ID
                oc.col_OrderSummaryID = currentOrderSummary.col_ID;
                // Add this record to the collection
                Globals.OrderCheckRecords.Add(oc);
            }
            // Remove any excess records, if they exist
            if (Globals.OrderCheckRecords.Count() > currentOrderSummary.col_Split)
            {
                int cnt = Globals.OrderCheckRecords.Count();
                for (int i = cnt; cnt > currentOrderSummary.col_Split; cnt--)
                {
                    await Globals.client.DeleteOrderCheckObjectAsync(Globals.token, Globals.OrderCheckRecords[cnt-1]);
                    Globals.OrderCheckRecords.RemoveAt(cnt - 1);
                }
            }
            // Display the payment selection dialog
            CloseOrder cod = new CloseOrder();
            //CloseCheckDialog cod = new CloseCheckDialog();
            //iCurrentSplitSeatNumber = 1;
            cod.iSplitCount = currentOrderSummary.col_Split;
            cod.iTableNO = currentOrderSummary.col_TableNumber;
            cod.iOrderNO = currentOrderSummary.col_ID;
            cod.iOrderDiscount = currentOrderSummary.col_DiscountID;
            // Set the header text...
            cod.setHeaderText("Select check #" + iCurrentSplitSeatNumber.ToString() + " items");
            cod.addOrderDetailItem(lvCurrentOrder.Items);
            cod.addChecks(currentOrderSummary.col_Split);
            
            cod.Width = Windows.UI.Xaml.Window.Current.Bounds.Width;
            cod.Height = Windows.UI.Xaml.Window.Current.Bounds.Height;
            cod.CloseRequested += CloseOrder_CloseRequested;
            //cod.CloseRequested += CloseCheckDialog_CloseRequested;
            dialogPopup = new Popup();
            dialogPopup.Child = cod;
            dialogPopup.IsOpen = true;
        }

        private async void CloseOrder_CloseRequested(object sender, EventArgs e)
        {
            CloseOrder ccd = (CloseOrder)sender;
            dialogPopup.IsOpen = false;
            if (e == null)//check if it is cancel 
            {
                return;
            }

            
            await closeCurrentOrder();

        }

        private void CloseCheckDialog_CloseRequested(object sender, EventArgs e)
        {
            // Determine the subtotal for the check...
            if (currentOrderSummary.col_Split>1)
            {

                foreach (OrderData od in lvCurrentOrder.Items)
                    if (od.Parent == null)
                    {
                        if (od.SeatNumber == iCurrentSplitSeatNumber - 1)
                        {
                            Globals.OrderCheckRecords[iCurrentSplitSeatNumber - 1].col_Subtotal += od.Price;
                            if (od.Options != null)
                            {
                                foreach (OrderData odp in od.Options)
                                {
                                    Globals.OrderCheckRecords[iCurrentSplitSeatNumber - 1].col_Subtotal += odp.Price;
                                }
                            }
                        }
                    }
            }
            else
            {
                // Check has not been split...
                foreach (OrderData od in lvCurrentOrder.Items)
                        Globals.OrderCheckRecords[0].col_Subtotal += od.Price;
            }
            // TODO: Calculate tax!
            // Close the dialog...
            dialogPopup.IsOpen = false;
            // Show a payment dialog, cash or credit
            CloseCheckDialog ccd = (CloseCheckDialog)sender;
            if (!ccd.bCanceled)
            {
                // Create a new popup
                dialogPopup = new Popup();
                if (ccd.bCash)
                {
                    // Show the cash payment dialog
                    CashPaymentDialog cpd = new CashPaymentDialog();
                    cpd.init(Globals.OrderCheckRecords[iCurrentSplitSeatNumber - 1].col_Subtotal, 0);
                    cpd.Width = Windows.UI.Xaml.Window.Current.Bounds.Width;
                    cpd.Height = Windows.UI.Xaml.Window.Current.Bounds.Height;
                    cpd.CloseRequested += CashPaymentDialog_CloseRequested;
                    dialogPopup = new Popup();
                    dialogPopup.Child = cpd;
                    dialogPopup.IsOpen = true;
                }
                else 
                {
                    // Show the credit payment dialog
                    CreditPaymentDialog cpd = new CreditPaymentDialog();
                    cpd.init(Globals.OrderCheckRecords[iCurrentSplitSeatNumber - 1].col_Subtotal, 0);
                    cpd.Width = Windows.UI.Xaml.Window.Current.Bounds.Width;
                    cpd.Height = Windows.UI.Xaml.Window.Current.Bounds.Height;
                    cpd.CloseRequested += CreditPaymentDialog_CloseRequested;
                    dialogPopup.Child = cpd;
                }
                // Show the dialog...
                dialogPopup.IsOpen = true;
            }
        }

        private async Task<bool> ProcessNextPayment()
        {            
            // Determine if another check needs to be closed...
            if ((currentOrderSummary.col_Split > 0) && (iCurrentSplitSeatNumber < currentOrderSummary.col_Split))
            {
                CloseCheckDialog ccd = new CloseCheckDialog();
                iCurrentSplitSeatNumber++;
                ccd.Width = Windows.UI.Xaml.Window.Current.Bounds.Width;
                ccd.Height = Windows.UI.Xaml.Window.Current.Bounds.Height;
                ccd.CloseRequested += CloseCheckDialog_CloseRequested;
                dialogPopup = new Popup();
                dialogPopup.Child = ccd;
                dialogPopup.IsOpen = true;
            }
            else
            {
                bool bAllPaid = true;
                // Determine if all associated checks have been paid
                foreach (ServiceReferenceOpenRPOS.OrderCheck oc in Globals.OrderCheckRecords)
                    bAllPaid &= oc.col_Paid;
                // Close the entire order if all checks have been paid...
                if (bAllPaid)
                    await closeCurrentOrder();
            }
            return true;
        }
        
        private async void CashPaymentDialog_CloseRequested(object sender, EventArgs e)
        {
            // Close the dialog...
            dialogPopup.IsOpen = false;
            // Show the wait dialog
            CashPaymentDialog cpd = (CashPaymentDialog)sender;
            // If the check has not been canceled, close it out...
            if (!cpd.bCanceled)
            {
                Globals.OrderCheckRecords[iCurrentSplitSeatNumber - 1].col_Paid = true;
                Globals.OrderCheckRecords[iCurrentSplitSeatNumber - 1].col_Gratuity = cpd.dGratuity;
                // Send the updated record...
                if (Globals.OrderCheckRecords[iCurrentSplitSeatNumber - 1].col_ID == 0)
                    // Need to add a new record
                    await Globals.client.AddOrderCheckObjectAsync(Globals.token, Globals.OrderCheckRecords[iCurrentSplitSeatNumber - 1]);
                else
                    // Update this record
                    await Globals.client.UpdateOrderCheckObjectAsync(Globals.token, Globals.OrderCheckRecords[iCurrentSplitSeatNumber - 1]);
            }
            // Process the next payment...
            await ProcessNextPayment();
        }
        private async void CreditPaymentDialog_CloseRequested(object sender, EventArgs e)
        {
            // Close the dialog...
            dialogPopup.IsOpen = false;
            // Show the wait dialog
            CreditPaymentDialog cpd = (CreditPaymentDialog)sender;
            // If the check has not been canceled, close it out...
            if (!cpd.bCanceled)
            {
                Globals.OrderCheckRecords[iCurrentSplitSeatNumber - 1].col_Paid = true;
                Globals.OrderCheckRecords[iCurrentSplitSeatNumber - 1].col_Gratuity = cpd.dGratuity;
                // ToDo: Add Auth Code!
                // Send the updated record...
                if (Globals.OrderCheckRecords[iCurrentSplitSeatNumber - 1].col_ID == 0)
                    // Need to add a new record
                    await Globals.client.AddOrderCheckObjectAsync(Globals.token, Globals.OrderCheckRecords[iCurrentSplitSeatNumber - 1]);
                else
                    // Update this record
                    await Globals.client.UpdateOrderCheckObjectAsync(Globals.token, Globals.OrderCheckRecords[iCurrentSplitSeatNumber - 1]);
            }
            // Process the next payment...
            await ProcessNextPayment();
        }
        private async void btnNew_Click(object sender, RoutedEventArgs e)
        {
            // Send the check (if needed)
            if (btnSend.IsEnabled)
                await sendOrder();
            // Disable the "close" button
            btnClose.IsEnabled = false;
            btnPrint.IsEnabled = false;
            // Disable the "split" button
            btnSplit.IsEnabled = false;
            // Disable the "new" button
            btnNew.IsEnabled = false;
            // Clear out the current order information
            lvCurrentOrder.Items.Clear();
            currentOrderSummary = new ServiceReferenceOpenRPOS.OrderSummary();
            recalculateTotal();
            await getOpenOrders();
            tbTable.Text = "0";
            OnNavButtonClick(grdNav.Children[0], null);
            cmbOpenOrders.SelectedIndex = -1;
        }

        private void cmbOpenOrders_DropDownClosed(object sender, object e)
        {
            if (currentOrderSummary.col_ID > 0 && cmbOpenOrders.SelectedIndex < 0)
            {
                cmbOpenOrders.SelectedIndex = orderSummaryIDList.IndexOf(currentOrderSummary.col_ID);
            }
        }

        private void tbTable_TextChanged(object sender, TextChangedEventArgs e)
        {
            // Re-enable the send button
            if (string.IsNullOrEmpty(tbTable.Text) == false && tbTable.Text != "0") btnSend.IsEnabled = true;
        }

        private void btnSplit_Click(object sender, RoutedEventArgs e)
        {
            //validate and ensure that order was splitted, if so load existing checks with menu items for each.
            if (currentOrderSummary.col_Split > 1 && currentOrderSummary.col_SplitEvenly == false)
            {
                SplitCheckByMenuItems((int)currentOrderSummary.col_Split);
            }
            else
            {
                SplitCheckDialog scd = new SplitCheckDialog();
                scd.Width = Windows.UI.Xaml.Window.Current.Bounds.Width;
                scd.Height = Windows.UI.Xaml.Window.Current.Bounds.Height;
                scd.CloseRequested += SplitCheckDialog_CloseRequested;
                dialogPopup = new Popup();
                dialogPopup.Child = scd;
                dialogPopup.IsOpen = true;
            }
        }
        private void SplitCheckDialog_CloseRequested(object sender, EventArgs e)
        {
            dialogPopup.IsOpen = false;
            SplitCheckDialog scd = (SplitCheckDialog)sender;
            if (!scd.bCanceled)
            {
                currentOrderSummary.bFilterSplit = true;
                currentOrderSummary.col_Split = (byte)scd.iSplitCount;
                currentOrderSummary.bFilterSplitEvenly = true;
                currentOrderSummary.col_SplitEvenly = scd.bSplitEvenly;
                // If the check is not split evenly, split it out by order items
                if (!scd.bSplitEvenly)
                {
                    // Initialize order detail split
                    foreach (OrderData od in lvCurrentOrder.Items)
                        od.SeatNumber = 0;
                    if (scd.iSplitCount > 1)
                    {
                        SplitCheckByMenuItems(scd.iSplitCount);
                    }
                }
            }
        }

        private void SplitCheckByMenuItems(int SplitCount)
        {
            // Create a new dialog to allow selection of menu items for first check...
            SplitMenuItemsDialog smid = new SplitMenuItemsDialog();
            smid.Width = Windows.UI.Xaml.Window.Current.Bounds.Width;
            smid.Height = Windows.UI.Xaml.Window.Current.Bounds.Height;
            smid.CloseRequested += SplitMenuItemsDialog_CloseRequested;
            dialogPopup = new Popup();
            dialogPopup.Child = smid;
            dialogPopup.IsOpen = true;
            iCurrentSplitSeatNumber = 1;
            smid.iCurrentSeat = iCurrentSplitSeatNumber;
            smid.iOrderNO = currentOrderSummary.col_ID;
            smid.iTableNO = currentOrderSummary.col_TableNumber;
            smid.iOrderDiscount = currentOrderSummary.col_DiscountID;
            // Set the header text...
            smid.setHeaderText("Select check #" + iCurrentSplitSeatNumber.ToString() + " items");
            // Add detail items to dialog
            
            foreach (OrderData od in lvCurrentOrder.Items)
                //if (od.Parent == null)
                smid.addOrderDetailItem(od);
            
            smid.iSplitCount = SplitCount;
            smid.addChecks(SplitCount);
        }

        private async void SplitMenuItemsDialog_CloseRequested(object sender, EventArgs e)
        {
            dialogPopup.IsOpen = false;

            SplitMenuItemsDialog scMenuItemdialog = (SplitMenuItemsDialog)sender;
            if (scMenuItemdialog != null) currentOrderSummary.col_Split = Convert.ToByte(scMenuItemdialog.iSplitCount);

            if (e == null)//check if it is cancel 
            {
                return;
            }
            // else send the order to save split checks count and menu items with appropriate seat number
            await sendOrder(true);
        }

        private void btnManager_Click(object sender, RoutedEventArgs e)
        {
            // Show the manager dialog...
            ManagerDialog md = new ManagerDialog();
            md.Width = Windows.UI.Xaml.Window.Current.Bounds.Width;
            md.Height = Windows.UI.Xaml.Window.Current.Bounds.Height;
            md.CloseRequested += ManagerDialog_CloseRequested;
            dialogPopup = new Popup();
            dialogPopup.Child = md;
            dialogPopup.IsOpen = true;
        }
        private async void ManagerDialog_CloseRequested(object sender, EventArgs e)
        {
            ManagerDialog md = (ManagerDialog)sender;
            dialogPopup.IsOpen = false;
            // Determine what option was selected...
            if (!md.bCanceled)
            {
                Page page = new Page();
                if (md.bDiscount)
                {
                    // Create a new "Discount" dialog
                    DiscountDialog dd = new DiscountDialog();
                    dd.CloseRequested += DiscountDialog_CloseRequested;
                    page = dd;
                }
                else if (md.bRefund)
                {
                    WaitPage waitPage = new WaitPage();
                    waitPage.Width = Windows.UI.Xaml.Window.Current.Bounds.Width;
                    waitPage.Height = Windows.UI.Xaml.Window.Current.Bounds.Height;
                    dialogPopup.Child = waitPage;
                    dialogPopup.IsOpen = true;
                    // Create a new "Refund" dialog
                    RefundDialog rd = new RefundDialog();
                    await rd.init();
                    rd.CloseRequested += RefundDialog_CloseRequested;
                    page = rd;
                    dialogPopup.IsOpen = false;
                }
                else if (md.bSettings)
                {
                    // Create a new "Settings" dialog
                    SettingsDialog sd = new SettingsDialog();
                    sd.CloseRequested += SettingsDialog_CloseRequested;
                    sd.init();
                    page = sd;
                }
                else if (md.bTipAdjust)
                {
                    WaitPage waitPage = new WaitPage();
                    waitPage.Width = Windows.UI.Xaml.Window.Current.Bounds.Width;
                    waitPage.Height = Windows.UI.Xaml.Window.Current.Bounds.Height;
                    dialogPopup.Child = waitPage;
                    dialogPopup.IsOpen = true;
                    // Create a new "Tip Adjustment" dialog
                    TipAdjustmentDialog tad = new TipAdjustmentDialog();
                    await tad.init();
                    tad.CloseRequested += TipAdjustmentDialog_CloseRequested;
                    page = tad;
                    dialogPopup.IsOpen = false;
                }
                else if (md.bVoid)
                {
                    WaitPage waitPage = new WaitPage();
                    waitPage.Width = Windows.UI.Xaml.Window.Current.Bounds.Width;
                    waitPage.Height = Windows.UI.Xaml.Window.Current.Bounds.Height;
                    dialogPopup.Child = waitPage;
                    dialogPopup.IsOpen = true;
                    // Create a new "Void" dialog
                    VoidDialog vd = new VoidDialog();
                    await vd.init();
                    vd.CloseRequested += VoidDialog_CloseRequested;
                    page = vd;
                    dialogPopup.IsOpen = false;
                }
                // Create a new dialog popup
                page.Width = Windows.UI.Xaml.Window.Current.Bounds.Width;
                page.Height = Windows.UI.Xaml.Window.Current.Bounds.Height;
                dialogPopup = new Popup();
                dialogPopup.Child = page;
                dialogPopup.IsOpen = true;
            }
        }
        private void SettingsDialog_CloseRequested(object sender, EventArgs e)
        {
            // Close the dialog...
            dialogPopup.IsOpen = false;
        }
        private async void VoidDialog_CloseRequested(object sender, EventArgs e)
        {
            // Close the dialog...
            dialogPopup.IsOpen = false;
            // Display wait cursor...
            WaitPage waitPage = new WaitPage();
            waitPage.Width = Windows.UI.Xaml.Window.Current.Bounds.Width;
            waitPage.Height = Windows.UI.Xaml.Window.Current.Bounds.Height;
            dialogPopup.Child = waitPage;
            dialogPopup.IsOpen = true;
            // Create a void for the current check...
            VoidDialog vd = (VoidDialog)sender;
            if (!vd.bCanceled)
            {
                if (vd.iCheckNumber > 0)
                {
                    ServiceReferenceOpenRPOS.Void voidRecord = new ServiceReferenceOpenRPOS.Void();
                    voidRecord.bFilterOrderCheckID = true;
                    voidRecord.col_OrderCheckID = vd.iCheckNumber;
                    voidRecord.bFilterLoginID = true;
                    voidRecord.bFilterReason = true;
                    voidRecord.col_Reason = vd.strReason;
                    voidRecord.col_LoginID = Globals.currentLogin.col_ID;
                    // Add the refund record
                    await Globals.client.AddVoidObjectAsync(Globals.token, voidRecord);
                }
            }
            // Close the wait cursor...
            dialogPopup.IsOpen = false;
        }
        private async void RefundDialog_CloseRequested(object sender, EventArgs e)
        {
            // Close the dialog...
            dialogPopup.IsOpen = false;
            // Display wait cursor...
            WaitPage waitPage = new WaitPage();
            waitPage.Width = Windows.UI.Xaml.Window.Current.Bounds.Width;
            waitPage.Height = Windows.UI.Xaml.Window.Current.Bounds.Height;
            dialogPopup.Child = waitPage;
            dialogPopup.IsOpen = true;
            // Create a refund for the current check...
            RefundDialog rd = (RefundDialog)sender;
            if (!rd.bCanceled)
            {
                if (rd.iCheckNumber > 0)
                {
                    ServiceReferenceOpenRPOS.Refund refund = new ServiceReferenceOpenRPOS.Refund();
                    refund.bFilterOrderCheckID = true;
                    refund.col_OrderCheckID = rd.iCheckNumber;
                    refund.bFilterAmount = true;
                    refund.bFilterLoginID = true;
                    refund.bFilterReason = true;
                    refund.col_Amount = rd.dRefundAmount;
                    refund.col_Reason = rd.strReason;
                    refund.col_LoginID = Globals.currentLogin.col_ID;
                    // Add the refund record
                    await Globals.client.AddRefundObjectAsync(Globals.token, refund);
                }
            }
            // Close the wait cursor...
            dialogPopup.IsOpen = false;
        }
        private async void TipAdjustmentDialog_CloseRequested(object sender, EventArgs e)
        {
            // Close the dialog...
            dialogPopup.IsOpen = false;
            // Display wait cursor...
            WaitPage waitPage = new WaitPage();
            waitPage.Width = Windows.UI.Xaml.Window.Current.Bounds.Width;
            waitPage.Height = Windows.UI.Xaml.Window.Current.Bounds.Height;
            dialogPopup.Child = waitPage;
            dialogPopup.IsOpen = true;
            // Adjust the tip for the selected check
            TipAdjustmentDialog tad = (TipAdjustmentDialog)sender;
            if (!tad.bCanceled && Globals.OrderCheckRecords.Count > 0)
            {
                ServiceReferenceOpenRPOS.OrderCheck oc = Globals.OrderCheckRecords[tad.iSelectedIndex];
                oc.bFilterGratuity = true;
                oc.col_Gratuity = tad.dTip;
                await Globals.client.UpdateOrderCheckObjectAsync(Globals.token, oc);
            }
            dialogPopup.IsOpen = false;
        }
        private async void DiscountDialog_CloseRequested(object sender, EventArgs e)
        {
            // Close the dialog...
            dialogPopup.IsOpen = false;
            // Display wait cursor...
            WaitPage waitPage = new WaitPage();
            waitPage.Width = Windows.UI.Xaml.Window.Current.Bounds.Width;
            waitPage.Height = Windows.UI.Xaml.Window.Current.Bounds.Height;
            Popup dp = new Popup();
            dp.Child = waitPage;
            dp.IsOpen = true;
            // Determine which discount was selected and the amount...
            DiscountDialog dd = (DiscountDialog)sender;
            // Determine whether or not the dialog was canceled 
            if (!dd.bCanceled)
            {
                // Create a new discount record
                ServiceReferenceOpenRPOS.Discount discountObject = new ServiceReferenceOpenRPOS.Discount();
                discountObject.bFilterAmount = true;
                discountObject.bFilterIsPercent = true;
                discountObject.bFilterLoginID = true;
                discountObject.col_Amount = dd.dAmount;
                discountObject.col_IsPercent = !dd.bDollarAmount;
                discountObject.col_LoginID = Globals.currentLogin.col_ID;
                discountObject.col_ID = await Globals.client.AddDiscountObjectAsync(Globals.token, discountObject);
                Globals.DiscountRecords.Add(discountObject);
                // Update the appropriate records
                if (dd.bEntireOrder)
                {
                    // Apply discount record to summary record
                    currentOrderSummary.bFilterDiscountID = true;
                    currentOrderSummary.col_DiscountID = discountObject.col_ID;
                    await Globals.client.UpdateOrderSummaryObjectAsync(Globals.token, currentOrderSummary);
                }
                else
                {
                    // Apply discount to selected records
                    foreach (OrderData od in lvCurrentOrder.SelectedItems)
                        od.DiscountID = discountObject.col_ID;
                    // Re-send the order to update discount information...
                    await sendOrder(false);
                }
                // Update the display with the discount information
                await loadSelectedOrder();
            }
            dp.IsOpen = false;
        }

        private void btnSend_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            // Don't enable "Close" if "Send" is enabled - Force sending before closing
            if (btnSend.IsEnabled)
                btnClose.IsEnabled = false;
            else 
                btnClose.IsEnabled = (lvCurrentOrder.Items.Count > 0);
            btnPrint.IsEnabled = btnClose.IsEnabled;
        }

        private void btnStatus_Click(object sender, RoutedEventArgs e)
        {
            // Display the status of all orders
            StatusDialog sd = new StatusDialog();
            sd.Width = Windows.UI.Xaml.Window.Current.Bounds.Width;
            sd.Height = Windows.UI.Xaml.Window.Current.Bounds.Height;
            sd.CloseRequested += StatusDialog_CloseRequested;
            sd.init();
            dialogPopup = new Popup();
            dialogPopup.Child = sd;
            dialogPopup.IsOpen = true;
        }
        private void StatusDialog_CloseRequested(object sender, EventArgs e)
        {
            // Close the dialog...
            dialogPopup.IsOpen = false;
        }

        private void btnFindTable_Click(object sender, RoutedEventArgs e)
        {
            // Present the Table Selection dialog
            TablePicker tp = new TablePicker();
            tp.Width = Windows.UI.Xaml.Window.Current.Bounds.Width;
            tp.Height = Windows.UI.Xaml.Window.Current.Bounds.Height;
            tp.CloseRequested += TablePickerDialog_CloseRequested;
            if(string.IsNullOrEmpty(tbTable.Text) ==false){
                tp.iTableNO =  Convert.ToInt32(tbTable.Text) ; //currentOrderSummary.col_TableNumber;
            }
            tp.init();
            dialogPopup = new Popup();
            dialogPopup.Child = tp;
            dialogPopup.IsOpen = true;
        }
        private void TablePickerDialog_CloseRequested(object sender, EventArgs e)
        {
            // Close the dialog...
            dialogPopup.IsOpen = false;
            // Update table number...
            TablePicker cod = (TablePicker)dialogPopup.Child;
            if (cod.bUpdated)
            {
                tbTable.Text = cod.tableNo;
                tbTable_TextChanged(tbTable, null);
            }
        }

        private void btnCarryOut_Click(object sender, RoutedEventArgs e)
        {
            // Present the carry out dialog
            CarryOutDialog cod = new CarryOutDialog();
            cod.Width = Windows.UI.Xaml.Window.Current.Bounds.Width;
            cod.Height = Windows.UI.Xaml.Window.Current.Bounds.Height;
            cod.CloseRequested += CarryOutDialog_CloseRequested;
            cod.init(currentOrderSummary);
            dialogPopup = new Popup();
            dialogPopup.Child = cod;
            dialogPopup.IsOpen = true;
        }
        private async void CarryOutDialog_CloseRequested(object sender, EventArgs e)
        {
            // Close the dialog...
            dialogPopup.IsOpen = false;            
            // Update carry out data...
            CarryOutDialog cod=(CarryOutDialog)dialogPopup.Child;
            if (cod.bUpdated)
            {
                currentOrderSummary.col_CarryOut = cod.orderSummary.col_CarryOut;
                currentOrderSummary.col_CustomerName = cod.orderSummary.col_CustomerName;
                currentOrderSummary.col_CustomerPhone = cod.orderSummary.col_CustomerPhone;
                currentOrderSummary.bFilterCustomerName = true;
                currentOrderSummary.bFilterCustomerPhone = true;
                await sendOrder();
            }
        }

        private async void btnPrint_Click(object sender, RoutedEventArgs e)
        {
            Globals.OrderCheckRecords = await Globals.client.GetOrderCheckObjectsAsync(Globals.token, "OrderSummaryID=" + currentOrderSummary.col_ID.ToString());
            // Ensure that the current summary record has at least 1 check associated with it
            if (currentOrderSummary.col_Split == 0)
                currentOrderSummary.col_Split = 1;
            // Determine if order checks exist for this check.  If not, create 1 for every split
            while (Globals.OrderCheckRecords.Count < currentOrderSummary.col_Split)
            {
                // Create a new order check record
                ServiceReferenceOpenRPOS.OrderCheck oc = new ServiceReferenceOpenRPOS.OrderCheck();
                // Set the filters
                oc.bFilterGratuity = true;
                oc.bFilterOrderSummaryID = true;
                //oc.bFilterPaid = true;
                //oc.bFilterPaymentType = true;
                oc.bFilterSeatNumber = true;
                oc.bFilterSubtotal = true;
                oc.bFilterTax = true;
                // Set the order summary ID
                oc.col_OrderSummaryID = currentOrderSummary.col_ID;
                oc.col_Subtotal = currentOrderSummary.col_Subtotal;
                // TODO: Update Tax Information!!!
                oc.col_Gratuity = 0.00M;
                oc.col_Tax = 0.00M;
                oc.col_SeatNumber = 0;
                // Add this record to the collection
                Globals.OrderCheckRecords.Add(oc);
                await Globals.client.AddOrderCheckObjectAsync(Globals.token, oc);
            }

            foreach (ServiceReferenceOpenRPOS.OrderCheck oc in Globals.OrderCheckRecords)
            {
                // Update the print queue to print the order reciepts
                ServiceReferenceOpenRPOS.PrintQueue pq = new ServiceReferenceOpenRPOS.PrintQueue();
                pq.bFilterPrintOrder = true;
                pq.col_PrintOrder = false;
                pq.bFilterPrintReceipt = true;
                pq.col_PrintReceipt = true;
                pq.bFilterOrderCheckID = true;
                pq.col_OrderCheckID = oc.col_ID;
                pq.bFilterOrderSummaryID = true;
                pq.col_OrderSummaryID = currentOrderSummary.col_ID;
                pq.bFilterPrinted = true;
                pq.col_Printed = false;
                await Globals.client.AddPrintQueueObjectAsync(Globals.token, pq);
            }
        }

    }

    public class OrderData
    {
        public OrderData()
        {
            FontColor = "Black";
        }
        public bool Discount { get; set; }
        public int DiscountID { get; set; }
        public string DisplayPrice { get; set; }
        public bool Exclude { get; set; }
        public bool Exclusive { get; set; }
        public string FontColor { get; set; }
        public int MenuItemID { get; set; }
        public string MenuItemName { get; set; }
        public List<OrderData> Options { get; set; }
        public OrderData Parent { get; set; }
        public int Portion { get; set; }
        public decimal Price { get; set; }
        public int SeatNumber { get; set; }
    }

}
